/**
 * @file    main.c 
 * @author  18408107475@163.com
 * @version V1.0.0
 * @date    2025-07-19
 * @brief   FreeRTOS多任务示例（LED闪烁+按键控制蜂鸣器）
 * @details 
 * 硬件配置：
 *   - 主控芯片：STM32F10x系列（如STM32F103C8T6）
 *   - 外设：
 *     - 绿色LED（PE5）：系统运行状态指示
 *     - 红色LED（PB5）：错误状态指示
 *     - 蜂鸣器：通过GPIO控制（具体引脚由BEEP_STD_Config.h定义）
 *     - 按键KEY1（PE3）：控制蜂鸣器开关（上拉输入，按下为低电平）
 *   - 连接说明：
 *     - LED采用共阳接法（阳极接3.3V，阴极接GPIO，低电平点亮）
 *     - 按键采用上拉输入（默认高电平，按下接地为低电平）
 * 
 * 软件特性：
 *   - 基于FreeRTOS实现多任务并发：
 *     - LED任务：周期性闪烁绿色LED，优先级较高
 *     - 蜂鸣器任务：轮询按键状态，控制蜂鸣器开关，优先级较低
 *   - 任务间无共享资源冲突（独立控制不同外设）
 *   - 硬件初始化在各自任务中完成，保证任务独立性
 */

/* Includes ------------------------------------------------------------------*/
/* Standard includes. */
#include <stdio.h>              // 标准输入输出库（预留，未实际使用）

/* Scheduler includes. */
#include "FreeRTOS.h"           // FreeRTOS核心头文件（任务、调度器定义）
#include "task.h"               // FreeRTOS任务管理函数（创建、延时等）
#include "queue.h"              // FreeRTOS队列头文件（预留，未实际使用）

/* project app includes. */
#include "LED_STD_Config.h"     // LED控制函数（初始化、亮灭控制）
#include "BEEP_STD_Config.h"    // 蜂鸣器控制函数（初始化、开关控制）
#include "USART1_Config.h"      // 串口调试功能（波特率配置、格式化输出）
#include "Delay.h"          	// 延时函数

/* Library includes. */
#include "stm32f10x.h"          // STM32F10x外设库（GPIO、RCC等寄存器定义）

/* Task priorities. */
/* 任务优先级定义：数值越大优先级越高 */
#define mainGREEN_LED_TASK_PRIORITY   	(tskIDLE_PRIORITY + 3)  // 绿色LED任务优先级（较高）
#define mainRED_LED_TASK_PRIORITY		(tskIDLE_PRIORITY + 2)  // 红色LED任务优先级（中等）
#define mainBEEP_TASK_PRIORITY  		(tskIDLE_PRIORITY + 1)  // 蜂鸣器任务优先级（较低）

/* 按键1硬件配置参数 */
#define KEY1_CLK					RCC_APB2Periph_GPIOE  // KEY1所在GPIO组时钟
#define KEY1_PORT					GPIOE                 // KEY1所在GPIO组
#define KEY1_PIN					GPIO_Pin_3            // KEY1引脚号

/*
 * Configure the KEY1 as required by the project.
 */
static void prvKey1_Config(void);  // KEY1初始化函数（静态，仅本文件可见）

/*
 * Configure the HardWare as required by the project.
 */
static void prvHardwareConfig(void);

TaskHandle_t	Green_LedTaskHandle = NULL;  // 绿色LED任务句柄（用于任务控制）
TaskHandle_t	Red_LedTaskHandle	= NULL;  // 红色LED任务句柄（用于任务控制）

/**
 * @brief  绿色LED闪烁任务函数
 * @param  pvParameters：任务参数（未使用，传入NULL）
 * @note   功能：
 *         1. 通过串口输出任务配置信息
 *         2. 实现绿色LED以500ms亮、500ms灭的周期闪烁
 *         3. 使用vTaskDelay实现精确延时，任务休眠时释放CPU资源
 *         4. 每次闪烁周期结束后恢复红色LED任务
 */
void vGreen_Led_Task(void *pvParameters)
{
	USART1_Printf("Green Led Task Config!!!\n\r");  // 串口输出任务配置完成信息

	// 任务主循环（无限循环，确保任务持续运行）
	for(;;){

		USART1_Printf("Green Led running!!!\n\r");	// 串口输出任务运行状态

		Green_Led_ON();               				// 绿色LED点亮（PE5输出低电平，共阳接法）
		USART1_Printf("Green ON!!!\n\r");
		vTaskDelay(pdMS_TO_TICKS(500));				// 延时500ms（任务阻塞，释放CPU）
		Green_Led_OFF();              				// 绿色LED熄灭（PE5输出高电平）
		USART1_Printf("Green OFF!!!\n\r");
		vTaskDelay(pdMS_TO_TICKS(500));				// 延时500ms（任务阻塞，释放CPU）

		vTaskResume(Red_LedTaskHandle);				// 恢复红色LED任务（触发红色LED闪烁一次）
	}
}

/**
 * @brief  红色LED任务函数
 * @param  pvParameters：任务参数（未使用，传入NULL）
 * @note   功能：
 *         1. 通过串口输出任务配置信息
 *         2. 实现红色LED以500ms亮、500ms灭的周期闪烁
 *         3. 每次亮灭周期结束后挂起自身，等待绿色LED任务恢复
 */
void vRed_Led_Task(void *pvParameters)
{
	USART1_Printf("Red Led Task Config!!!\n\r");  	// 串口输出任务配置完成信息

	for(;;){
		USART1_Printf("Red Led running!!!\n\r");  	// 串口输出任务运行状态

		Red_Led_OFF();								// 红色LED熄灭（共阳接法，高电平熄灭）
		USART1_Printf("Red OFF!!!\n\r");
		vTaskDelay(pdMS_TO_TICKS(500));         	// 延时500ms
		Red_Led_ON();                           	// 红色LED点亮（低电平点亮）
		USART1_Printf("Red ON!!!\n\r");
		vTaskDelay(pdMS_TO_TICKS(500));         	// 延时500ms

		vTaskSuspend(Red_LedTaskHandle);     	 	// 挂起红色LED任务（等待绿色LED任务恢复）
	}
}

/**
 * @brief  蜂鸣器控制任务函数
 * @param  pvParameters：任务参数（未使用，传入NULL）
 * @note   功能：
 *         1. 通过串口输出任务配置信息
 *         2. 轮询检测KEY1按键状态
 *         3. 按键按下时开启蜂鸣器，释放时关闭
 *         4. 包含按键消抖逻辑（通过延时实现）
 *         5. 每次循环结束后自我挂起（存在潜在逻辑问题，任务可能无法恢复）
 */
void vBuzer_Task(void *pvParameters)
{
	USART1_Printf("Buzzer Config!!!\n\r");  				// 串口输出任务配置完成信息

	for(;;){

		USART1_Printf("Buzzer running!!!\n\r");  			// 串口输出任务运行状态
		
		// 检测KEY1是否按下（输入低电平，上拉输入模式）
		if(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
			Beep_ON();  									// 开启蜂鸣器
			
			// 等待按键释放（循环检测，每10ms延时一次）
			while(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
				vTaskDelay(10);  							// 短暂延时，降低CPU占用，同时实现消抖
			}
			
			Beep_OFF();  									// 关闭蜂鸣器
		}
		
		vTaskSuspend(NULL);  								// 自我挂起（存在潜在逻辑问题：任务挂起后无法自动恢复）
		vTaskDelay(10);      								// 轮询间隔10ms，平衡响应速度与CPU负载（此代码行不会执行）
	}
}

/**
 * @brief  主程序入口
 * @param  None
 * @retval int 程序状态码（实际不会返回，因调度器启动后接管系统）
 * @执行流程：
 *   1. 初始化系统硬件（LED、蜂鸣器、按键、串口）
 *   2. 创建三个FreeRTOS任务（绿色LED、红色LED、蜂鸣器控制）
 *   3. 检查任务创建结果，失败则通过红色LED常亮报警
 *   4. 启动FreeRTOS调度器，开始任务调度
 */
int main(void)
{
	prvHardwareConfig();  // 初始化系统硬件

	BaseType_t 		xReturned;        	// 任务创建返回值（pdPASS表示成功）
	
	// 创建绿色LED闪烁任务
	xReturned = xTaskCreate(
		vGreen_Led_Task,                // 任务函数
		"Green_Led",                    // 任务名称（用于调试和识别）
		configMINIMAL_STACK_SIZE,       // 任务栈大小（使用最小配置）
		NULL,                        	// 任务参数（未使用）
		mainGREEN_LED_TASK_PRIORITY,    // 任务优先级（最高）
		&Green_LedTaskHandle           	// 任务句柄输出（用于任务控制）
	);
	
	// 创建蜂鸣器控制任务（不保存任务句柄，因无需后续操作）
	xTaskCreate(
		vBuzer_Task, 
		"Key control Beep", 
		configMINIMAL_STACK_SIZE, 
		NULL, 
		mainBEEP_TASK_PRIORITY, 
		NULL
	);

	// 创建红色LED任务
	xTaskCreate(
		vRed_Led_Task,
		"Red_Led",
		configMINIMAL_STACK_SIZE,
		NULL,
		mainRED_LED_TASK_PRIORITY,
		&Red_LedTaskHandle
	);

	// 检查绿色LED任务创建结果（失败处理）
	if(xReturned != pdPASS){
		// 任务创建失败：红色LED常亮
		for(;;){
			Red_Led_ON();               		// 点亮红色LED（PB5输出低电平）
			vTaskDelay(pdMS_TO_TICKS(100));		// 延时（调度器未启动时无效，实际常亮）
		}
	}

	// 启动FreeRTOS任务调度器（从此处开始，系统由调度器管理）
	vTaskStartScheduler();

    // 调度器启动后不会执行到此处
    while (1)                  
    {
        
    }
}

/**
 * @brief  配置KEY1为上拉输入模式
 * @note   硬件逻辑：
 *         - KEY1按下时接地（输入低电平）
 *         - 未按下时，内部上拉电阻使输入为高电平
 *         - 无需外部上拉电阻，简化硬件设计
 *         - GPIO_Speed参数在输入模式下无效，仅为结构体完整性设置
 */
static void prvKey1_Config(void)
{
	// 使能KEY1所在GPIO组时钟
	RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);

	// 初始化GPIO参数结构体
	GPIO_InitTypeDef GPIO_InitStructure = {
		.GPIO_Mode 	= GPIO_Mode_IPU,      		// 上拉输入模式
		.GPIO_Pin 	= KEY1_PIN,           		// 对应引脚
		.GPIO_Speed = GPIO_Speed_50MHz,   		// 输入模式下速度参数无效
	};

	// 应用配置到指定GPIO组
	GPIO_Init(KEY1_PORT, &GPIO_InitStructure);
}

/**
 * @brief  初始化系统硬件
 * @note   配置顺序：LED → 蜂鸣器 → 按键 → 串口
 *         确保外设按依赖关系正确初始化
 */
static void prvHardwareConfig(void)
{
	// 初始化LED硬件：配置PB5、PE5为推挽输出，初始为高电平（LED熄灭）
	LED_STD_Config();
	BEEP_STD_Config();  		// 初始化蜂鸣器硬件（配置对应GPIO为推挽输出）
	prvKey1_Config();   		// 初始化KEY1为上拉输入
	USART1_Config(115200);  	// 初始化USART1，波特率115200

}
/************************ (C) COPYRIGHT  END OF FILE************************/